from Definition import Definition
from Detect import Detect
from FileDetect import FileDetect
import logging


class InputDefinition(Definition):
	def __init__(self, file):
		super().__init__(file)
		self.detector = Detect()
		self.file_detector = FileDetect()
		self.types = set([listener.get('type') for listener in self.get_listeners()])

	def needs_detect(self):
		listeners = self.get_listeners()
		for listener in listeners:
			if listener.get('type') == 'file':
				return False
			location = listener.get('location')
			if location is None:
				return True
		return False

	def get_listeners(self):
		listeners = self.content.get('listeners')
		if listeners is None:
			raise(Exception('invalid input definition, missing listeners'))
		return listeners

	def detect(self):
		listeners = self.get_listeners()
		for listener in listeners:
			location = listener.get('location')
			if location is None:
				detect = self._get_detect(listener)
				detectet_location, error = self._detect_location(detect)
				if error is not None:
					return error
				listener['location'] = {'x': detectet_location[0], 'y': detectet_location[1]}
		return 'detected'

	def get_single_detect(self, index):
		listeners = self.get_listeners()
		listener = listeners[index]
		detect = self._get_detect(listener)
		detectet_location, error = self._detect_location(detect)
		return detectet_location, error

	def _get_detect(self, listener):
		detect = listener.get('detect')
		if detect is None:
			raise(Exception('invalid input definition, missing listener detect or location'))
		return detect

	def _detect_location(self, detect):
		match = (detect['r'], detect['g'], detect['b'])
		matches = self.detector.find_matches(match)
		if len(matches) == 1:
			return matches[0], None
		logging.warning('could not match ' + str(detect) + ', found ' + str(len(matches)) + ' valid candidates')
		return None, 'detection failed, found ' + str(len(matches))

	def get_values(self):
		listeners = self.get_listeners()
		if 'pixel' in self.types:
			image = self.detector.capture()
			image_map = image.load()

		captured_input = []
		for listener in listeners:
			listener_type = listener.get('type')
			if listener_type is None or listener_type == 'pixel':
				self.get_pixel_value(listener, captured_input, image_map)
			elif listener_type == 'file':
				self.get_file_value(listener, captured_input)

		return captured_input

	def get_file_value(self, listener, captured_input):
		location = listener['location']
		default = listener.get('default')
		listener_result = None

		listener_result = self.file_detector.match(location, listener['states'])
		if listener_result is None:
			listener_result = default

		captured_input.append(listener_result)

	def get_pixel_value(self, listener, captured_input, image_map):
		location = listener.get('location')
		default = listener.get('default')
		value = image_map[location['x'], location['y']]
		listener_result = None
		for state in listener['states']:
			name = state.get('name')
			if self._match_state(state, value):
				listener_result = name
				continue
		if listener_result is None:
			listener_result = default
		captured_input.append(listener_result)

	def _match_state(self, state, value):
		detect_r = value[0]
		detect_g = value[1]
		detect_b = value[2]
		condition = state['condition']
		condition_r = condition.get('r')
		operator_r = condition.get('r_operator')
		condition_g = condition.get('g')
		operator_g = condition.get('g_operator')
		condition_b = condition.get('b')
		operator_b = condition.get('b_operator')

		if (
			self._match_state_value(detect_r, operator_r, condition_r) and
			self._match_state_value(detect_g, operator_g, condition_g) and
			self._match_state_value(detect_b, operator_b, condition_b)
		):
			return True
		return False

	def _match_state_value(self, detect, operator, condition):
		if condition is None:
			return True

		if operator is None or operator == '==' or operator == '=':
			return detect == condition
		elif operator == '!=' or operator == '<>':
			return detect != condition
		elif operator == '>':
			return detect > condition
		elif operator == '<':
			return detect < condition
		elif operator == '<=':
			return detect <= condition
		elif operator == '>=':
			return detect >= condition

	@classmethod
	def read(cls):
		return cls.read_folder('input')
